package org.platform.processor.monitor.job;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.platform.mo.bussmo.diagnose.event.AbnormalEventBO;
import org.platform.mo.bussmo.diagnose.event.AlarmBO;
import org.platform.mo.bussmo.diagnose.event.DevicePropertyBO;
import org.platform.mo.bussmo.diagnose.event.StandardEventBO;
import org.platform.processor.knowledge.EventProcessor;
import org.platform.processor.monitor.data.CacheLibraryPO;
import org.platform.tool.util.ComUtils;
import org.platform.tool.util.TimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.Queue;

/**
 * 第三步: 用属性队列属性值和标准属性值比较的线程
 * 如果有问题,就存入异常队列里
 *
 * @author FengJie
 * @date 2018/5/17
 */


@Service
@Slf4j
public class ComparePropertyJob {
    private static final int COMPARE_THREAD_COUNT = 0;
    private static final int COMPARE_SLEEP_TIME = 50;

    @Autowired
    private EventProcessor service;


    @PostConstruct
    private void init() {
        for (int i = 0; i < COMPARE_THREAD_COUNT; i++) {
            CompareThread compareThread = new CompareThread();
            compareThread.setName("Compare" + i);
            compareThread.start();
        }
    }

    class CompareThread extends Thread {
        /**
         * 标准参考源
         */
        private Map<String, List<StandardEventBO>> standardMap = CacheLibraryPO.getCacheLibraryPO().getStandardReferenceSourceMap();
        /**
         * 本队列用于存储拆解deviceQueue 之后的单个属性值
         */
        private Queue<DevicePropertyBO> propertyQueue = CacheLibraryPO.getCacheLibraryPO().getDevicePropertyQueue();
        /**
         * 本对列存放有异常的设备
         */
        private Map<String, AbnormalEventBO> abnormalDeviceMap = CacheLibraryPO.getCacheLibraryPO().getAbnormalDeviceMap();
        /**
         * 本集合用于存放[报警]设备的的最新属性值,判断报警的设备是否恢复正常
         */
        private Map<String, DevicePropertyBO> latestAlarmDevicePropertyMap = CacheLibraryPO.getCacheLibraryPO().getLatestAlarmDevicePropertyMap();


        /**
         * 从队列里面去设备属和标准参考源做比较
         * 数值型:
         * (最小正常值< 设备属性值  < 最大正常值)  结果:(正常) || (最小异常值 < 设备属性值< 最大异常值) 结果(异常)
         * 枚举值:
         * 设备属性值==枚举值(异常枚举值)   结果:(异常) 反之...
         */
        @Override
        @SuppressWarnings("InfiniteLoopStatement")
        public void run() {
            while (true) {
                try {
                    DevicePropertyBO property = propertyQueue.poll();
                    if (null != property) {
                        String propertyKey = StringUtils.join(property.getDeviceId(), "_", property.getPropertyName());
                        if (standardMap.containsKey(propertyKey)) {
                            List<StandardEventBO> monitorList = standardMap.get(propertyKey);
                            for (StandardEventBO monitor : monitorList) {
                                switch (monitor.getAttrtype()) {
                                    case 0:
                                        double propertyValue = Double.parseDouble(property.getPropertyValue());
                                        if (null != monitor.getErrormaxval()) {
                                            if (propertyValue <= monitor.getErrormaxval()
                                                    && propertyValue >= monitor.getErrorminval()) {
                                                addAbnormalMap(property, monitor);
                                            } else {
                                                determineWhetherRestoration(property);
                                            }
                                        }
                                        if (null != monitor.getMaxval()) {
                                            if (propertyValue > monitor.getMaxval()
                                                    || propertyValue < monitor.getMinval()) {
                                                addAbnormalMap(property, monitor);
                                            } else {
                                                determineWhetherRestoration(property);
                                            }
                                        }
                                        break;
                                    case 1:
                                        if (monitor.getEnumval().equals(property.getPropertyValue())) {
                                            addAbnormalMap(property, monitor);
                                        } else {
                                            determineWhetherRestoration(property);
                                        }
                                        break;
                                    default:
                                }
                            }
                        }
                    } else {
                        Thread.sleep(COMPARE_SLEEP_TIME);
                    }
                } catch (Exception e) {
                    log.error("属性设备属性和标准源比较异常: ", e);
                }
            }
        }

        /**
         * 增加异常设备到告警列表
         * 判断是不是第一次入库:
         * 1.如果是第一次入库,初始化错误次数,以及对应的信息
         * 2.如果不是第一次入库,则累加错误次数,(注意:这里不用更新当前设备的时间,主要方便后面是否在异常库中删除单前异常_
         */
        void addAbnormalMap(DevicePropertyBO property, StandardEventBO standardEventBO) {

            //异常库map中 key的设计:设备id_属性id_知识id
            String key = StringUtils.join(standardEventBO.getDeviceid(), "_", standardEventBO.getAttrid(), "_", standardEventBO.getKnowledgeid());

            if (abnormalDeviceMap.containsKey(key)) {
                //判断报警的间隔时间为一秒
                String format = "yyyy-MM-dd HH:mm:ss.SSS";
                int errorTimeInterval = 1000;

                AbnormalEventBO abnormalEventBO = abnormalDeviceMap.get(key);
                long latestTime = TimeUtils.strTimeToTimestampsByFormat(property.getTimeSpan(), format);
                long lastTime = TimeUtils.strTimeToTimestampsByFormat(abnormalEventBO.getTimeSpan(), format);
                //判断报警的间隔时间为一秒
                if (errorTimeInterval == lastTime - latestTime) {
                    abnormalEventBO.setCountByTime(abnormalEventBO.getCountByTime() + 1);
                }
                abnormalEventBO.setCount(abnormalEventBO.getCount() + 1);
                abnormalEventBO.setPropertyValue(property.getPropertyValue());
            } else {
                AbnormalEventBO abnormalEventBO = new AbnormalEventBO();
                abnormalEventBO.setCount(1);
                abnormalEventBO.setCountByTime(1);
                abnormalEventBO.setPropertyValue(property.getPropertyValue());
                abnormalEventBO.setDeviceId(property.getDeviceId());
                abnormalEventBO.setTimeSpan(property.getTimeSpan());
                abnormalEventBO.setPropertyName(property.getPropertyName());
                abnormalEventBO.setStandardEventBO(standardEventBO);
                abnormalDeviceMap.put(key, abnormalEventBO);
            }
        }

        /**
         * 该方法主要用于判报警库的设备是否恢复正常:
         * 如果当前设备是正常值,同时存在于报警库里面,即说明当前的设备是恢复正常了:
         * 1.需要从报警库里面删除设备信息
         * 2.更新数据库,已经恢复正常
         */
        void determineWhetherRestoration(DevicePropertyBO property) {
            String key = property.getDeviceId() + "_" + property.getPropertyName();
            latestAlarmDevicePropertyMap.forEach((k, v) -> {
                if (k.contains(key)) {
                    AlarmBO alarmBO = new AlarmBO();
                    alarmBO.setIsrestored(1);
                    alarmBO.setRestoretime(TimeUtils.strTimeToTimestampsByFormat(v.getTimeSpan(), null));
                    alarmBO.setDeviceid(v.getDeviceId());
                    alarmBO.setDevattr(v.getPropertyName());
                    alarmBO.setDevattrval(ComUtils.objectToString(v.getPropertyValue()));
                    service.addOrModifyEventByStation(alarmBO);
                    latestAlarmDevicePropertyMap.remove(k);
                }
            });
        }
    }
}
